#ifndef EVM_TIMER_QUEUE_H
#define EVM_TIMER_QUEUE_H

#include <deque>
#include <functional>
#include <chrono>


namespace evm {
    namespace http {

        using namespace std;

        struct TimerQueue {
            TimerQueue(int tick) : tick_(tick) {}

            uint64_t put(function<void ()> f) {
                queue_.emplace_back(chrono::steady_clock::now(), std::move(f));
                return n_processed_ + queue_.size();  // timer item key
            }

            void cancel(uint64_t& key) {
                if (key == 0)
                    return;

                size_t index = static_cast<size_t>(key - n_processed_ - 1);
                if (index < queue_.size())
                    queue_[index].second = nullptr;  // cancel timer item
                key = 0;  // 0 means cancelled timer item
            }

            void get() {
                while (!queue_.empty()) {
                    const auto& front = queue_.front();
                    if (chrono::steady_clock::now() - front.first < chrono::seconds(tick_))
                        break;  // has not pass tick seconds
                    if (front.second)
                        front.second();  // execute timer call
                    queue_.pop_front();
                    ++n_processed_;
                }
            }

        private:
            deque<pair<decltype(chrono::steady_clock::now()), function<void ()>>> queue_;
            int tick_;
            uint64_t n_processed_{};
        };

    }
}

#endif //EVM_TIMER_QUEUE_H
